package com.aruba.attendance.home.viewmodel

import android.Manifest
import android.content.Intent
import androidx.activity.result.ActivityResultLauncher
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.room.withTransaction
import com.aruba.attendance.database.AppDatabase
import com.aruba.attendance.database.dao.OverworkDurationDao
import com.aruba.attendance.database.dao.RecordDao
import com.aruba.attendance.database.dao.insertOrUpdate
import com.aruba.attendance.database.entity.RecordEntity
import com.aruba.attendance.extension.photo.photo
import com.aruba.attendance.util.TimeUtil
import com.ctrip.flight.mmkv.MMKV_KMP
import com.tbruyelle.rxpermissions3.RxPermissions
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.launch
import java.util.*
import javax.inject.Inject

/**
 * Created by aruba on 2023/2/13.
 */
@HiltViewModel
class HomeViewModel @Inject constructor(
    private val kv: MMKV_KMP,
    private val appDatabase: AppDatabase
) : ViewModel() {
    @Inject
    lateinit var recordDao: RecordDao

    @Inject
    lateinit var overworkDurationDao: OverworkDurationDao

    // 照片保存地址
    private lateinit var outPath: String

    fun findRecordByDate(year: Int, month: Int, dayOfMonth: Int): Flow<List<RecordEntity>> {
        return recordDao.findRecordFlowByDate(year, month, dayOfMonth).flowOn(Dispatchers.IO)
    }

    fun findDurationSumFlow(): Flow<Long?> {
        return overworkDurationDao.findDurationSum().flowOn(Dispatchers.IO)
    }

    fun findDurationFlowByDate(
        year: Int,
        month: Int,
        dayOfMonth: Int
    ): Flow<Long?> {
        return overworkDurationDao.findDurationFlowByDate(year, month, dayOfMonth)
            .flowOn(Dispatchers.IO)
    }

    private suspend fun insertRecordEntity(
        recordEntity: RecordEntity,
        insertCompleteCallback: (() -> Unit)? = null
    ) {
        recordDao.insert(recordEntity)
        insertCompleteCallback?.invoke()
    }

    fun toPhoto(
        activity: FragmentActivity,
        activityResult: ActivityResultLauncher<Intent>,
        callback: (denial: Boolean) -> Unit = {}
    ) {
        activity.apply {
            RxPermissions(this)
                .request(Manifest.permission.CAMERA)
                .subscribe { granted ->
                    if (granted) {
                        outPath = photo(activityResult, getExternalFilesDir(null)!!.absolutePath)
                        callback(false)
                    } else {
                        callback(true)
                    }
                }
        }
    }

    fun saveRecord(saveCompleteCallback: (() -> Unit)? = null) {
        viewModelScope.launch {
            val date = Calendar.getInstance()
            val year = date.get(Calendar.YEAR)
            val month = date.get(Calendar.MONTH) + 1
            val dayOfMonth = date.get(Calendar.DAY_OF_MONTH)

            val recordList = recordDao.findRecordByDate(year, month, dayOfMonth)
            val recordEntity = RecordEntity(
                year,
                month,
                dayOfMonth,
                TimeUtil.hour2String(date.get(Calendar.HOUR_OF_DAY)) +
                        TimeUtil.minute2String(date.get(Calendar.MINUTE)),
                outPath
            )

            appDatabase.withTransaction {
                // 计算时长 
                var duration = TimeUtil.calcDuration(
                    kv.takeString("endTime"),
                    recordEntity.time
                )
                if (recordList.isEmpty() && duration < 0) {
                    recordEntity.type = RecordEntity.TYPE_GO_WORK
                } else {
                    recordEntity.type = RecordEntity.TYPE_OFF_WORK
                }

                if ((date.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY ||
                            date.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY)
                ) {// 周末则以首次打卡时间为准
                    if (recordList.isNotEmpty()) {
                        duration = TimeUtil.calcDuration(
                            recordList[0].time,
                            recordEntity.time
                        )
                        // 更新或插入加班时长
                        overworkDurationDao.insertOrUpdate(year, month, dayOfMonth, duration)
                    }
                } else {// 工作日直接插入或更新
                    // 更新或插入加班时长
                    overworkDurationDao.insertOrUpdate(year, month, dayOfMonth, duration)

                    // 迟到时间
                    if(RecordEntity.TYPE_GO_WORK == recordEntity.type) {
                        val delayDuration = TimeUtil.calcDuration(
                            kv.takeString("startTime"),
                            recordEntity.time
                        )
                        recordEntity.delayDuration = delayDuration
                    }
                }

                // 插入打卡记录
                insertRecordEntity(recordEntity) {
                    saveCompleteCallback?.invoke()
                }
            }
        }
    }

}